package com.informatics.polymer.server;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;

import com.informatics.polymer.server.Polymerisation.BlockCopolymerisation;
import com.informatics.polymer.server.Polymerisation.PolymerisationUtils;
import com.informatics.polymer.server.Polymerisation.RandomCopolymerisation;
/**
 * Restlet to implement random copolymerization, it takes parameters from the GWT GUI then builds the
 * polymer using the polymerization API and returns the resultant XML to JMol for viewing.
 * @author ed
 * @version 1.0
 */
public class RandomCopolymerBuilder extends Resource {
	/**
	 * String representation of endGroup1.
	 */
	private String eg1;
	/**
	 * String representation of the repeat unit A.
	 */
	private String repeatUnitA;
	/**
	 * String representation of repeat unit B.
	 */
	private String repeatUnitB;
	/**
	 * String representation of endGroup2.
	 */
	private String endGroup2;
	/**
	 * Double value for the torsion angle.
	 */
	private double torsionAngle;
	/**
	 * Double value for probability of monomer A occurring after monomer A.
	 */
	private double pAA;
	/**
	 * Double value for probability of monomer A occurring after monomer B.
	 */
	private double pBA;
	/**
	 * Double value for probability of termination after monomer A.
	 */
	private double pTA;
	/**
	 * Double value for probability of termination after monomer B.
	 */
	private double pTB;
	/**
	 * Double value for probability of monomer B after monomer B.
	 */
	private double pBB;
	/**
	 * Double value for probability of monomer B occurring after monomer A.
	 */
	private double pAB;
	//Getters and setters.
	/**
	 * Set pAA.
	 * @param pAAValue - double value representing the probability of AA.
	 */
	private void setPAA(double pAAValue){
		this.pAA = pAAValue;
	}
	/**
	 * Gets probability of AA.
	 * @return double value representing the probability of AA.
	 */
	private double getPAA(){
		return pAA;
	}
	/**
	 * Set pAB
	 * @param pABValue - double value representing the probability of AB.
	 */
	private void setPAB(double pABValue){
		this.pAB = pABValue;
	}
	/**
	 * Gets probability of AB.
	 * @return double value representing the probability of AB.
	 */
	private double getPAB(){
		return pAB;
	}
	/**
	 * Sets pTA.
	 * @param pTAValue - double value representing the probability of termination after A.
	 */
	private void setPTA(double pTAValue){
		this.pTA = pTAValue;
	}
	/**
	 * Gets probability of termination after A.
	 * @return pTA - double value representing the probability of termination.
	 */
	private double getPTA(){
		return pTA;
	}
	/**
	 * Sets probability of BA.
	 * @param pBAValue - double value representing the probability of BA.
	 */
	private void setPBA(double pBAValue){
		this.pBA = pBAValue;
	}
	/**
	 * Gets probability of BA.
	 * @return pBA - probability of BA.
	 */
	private double getPBA(){
		return pBA;
	}
	/**
	 * Set probability of pBB.
	 * @param pBBValue - probability of BB.
	 */
	private void setPBB(double pBBValue){
		this.pBB = pBBValue;
	}
	/**
	 * Get probability of pBB.
	 * @return pBB - probability of pBB.
	 */
	private double getPBB(){
		return pBB;
	}
	/**
	 * Set pTB.
	 * @param pTBValue - probability of termination after B.
	 */
	private void setPTB(double pTBValue){
		this.pTB = pTBValue;
	}
	/**
	 * Get pTB.
	 * @return pTB - double representing the probability of termination after B.
	 */
	private double getPTB(){
		return pTB;
	}
	/**
	 * Sets endGroup1 value.
	 */
	private void setEG1(String val){
		this.eg1 = val;
	}
	/**
	 * Gets endGroup1.
	 * @return String representation of endGroup1.
	 */
	private String getEG1(){
		return eg1;
	}
	/**
	 * Sets the repeat unit.
	 * @param repeatUnitValue - String representation of the repeat unit.
	 */
	private void setRepeatUnit(String repeatUnitValue){
		this.repeatUnitA = repeatUnitValue;
	}
	/**
	 * Gets repeat unit.
	 * @return String representation of the repeat unit.
	 */
	private String getRepeatUnit(){
		return repeatUnitA;
	}
	/**
	 * Sets repeat unit B.
	 * @param repeatUnitValue - String representation of repeat unit B.
	 */
	private void setRepeatUnitB(String repeatUnitValue){
		this.repeatUnitB = repeatUnitValue;
	}
	/**
	 * Gets repeat unit B.
	 * @return String representation of repeat unit B.
	 */
	private String getRepeatUnitB(){
		return repeatUnitB;
	}
	/**
	 * Sets endGroup2.
	 * @param endGroup2 - String representation of endGroup2.
	 */
	private void setEndGroup2(String endGroup2){
		this.endGroup2 = endGroup2;
	}
	/**
	 * Gets endGroup2.
	 * @return String representation of endGroup2.
	 */
	private String getEndGroup2(){
		return endGroup2;
	}
	/**
	 * Sets the torsion angle.
	 * @param tAngle - Double value representing the torsion.
	 */
	private void setTorsionAngle(double tAngle){
		this.torsionAngle = tAngle;
	}
	/**
	 * Gets the torsion angle.
	 * @return Double representing the torsion angle.
	 */
	private double getTorsionAngle(){
		return torsionAngle;
	}
	
	/**
	 * Initiate the restlet.
	 */
	public void init(Context context, Request request, Response response) {
		super.init(context, request, response);
	//	getVariants().add(Constants.XML_VARIANT);
		getVariants().add(new Variant(MediaType.TEXT_PLAIN));
		this.setModifiable(true);
	}
	/**
	 * Method allows forms to be posted to restlet.
	 */
	@Override
	public boolean allowPost() {
		return true;
	}
	/**
	 * Constructs Random copolymerBuilder resource.
	 * @param context 
	 * @param request
	 * @param response
	 */
	public RandomCopolymerBuilder(Context context, Request request, Response response){
		super(context,request,response);
		getVariants().add(new Variant(MediaType.TEXT_PLAIN));
	}

	/**
	 * Method deals with the form posted to the restlet.
	 */
	@Override
	public void post(Representation entity) {
		// Get the URLs and polymerisation parameters from the request (getRequest)
		Form form = new Form(entity); 
		setEG1(form.getValues("endGroup1"));
		setRepeatUnit(form.getValues("repeatUnit"));
		setRepeatUnitB(form.getValues("repeatUnitB"));
		setEndGroup2(form.getValues("endGroup2"));
		setTorsionAngle(Double.parseDouble(form.getValues("torsionAngle")));
		String counterValue =  form.getValues("counter");
		//Double p-values need to be set.
		setPAA(Double.parseDouble(form.getValues("pAA")));
		setPBA(Double.parseDouble(form.getValues("pBA")));
		setPTA(Double.parseDouble(form.getValues("pTA")));
		setPBB(Double.parseDouble(form.getValues("pBB")));
		setPAB(Double.parseDouble(form.getValues("pAB")));
		setPTB(Double.parseDouble(form.getValues("pTB")));
		RandomCopolymerisation randomCopolymerisation = new RandomCopolymerisation(getPAA(),getPAB(),getPTA(),getPBA(),getPBB(),getPTB(),getTorsionAngle(),
				 getRepeatUnit(),getRepeatUnitB(),getEG1(),getEndGroup2());
		String randomCopolymerNoCoords = randomCopolymerisation.getPolymer().toXML();
		//String blockCopolymerNoCoords = blockCopolymerisation.generatePML();
		String polymerWith3DCoords = null;
		try {
			polymerWith3DCoords = PolymerisationUtils.add3DCoordinates(randomCopolymerNoCoords);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String finalResult = polymerWith3DCoords;
		StringRepresentation str = new StringRepresentation(finalResult);
		//Write out to a file
		String f = "/RandomCopolymer"+counterValue+".cml";
		String curDir = new String(System.getProperty("user.dir"));
		File homopolymerXml = new File(curDir+f);
		BufferedWriter out;
		//Use apache io
		try {
			FileUtils.writeStringToFile(homopolymerXml, finalResult);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			out = new BufferedWriter(new FileWriter(curDir+f));
			out.write(finalResult);
		    out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
       
		getResponse().setEntity(str);
	}

	// Respond to GET
	public Representation represent (Variant variant) throws ResourceException{
		Representation resource = null;
			if (!MediaType.TEXT_PLAIN.includes(variant.getMediaType())) {
				throw new ResourceException(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
			}
			else{
				StringBuffer sb = new StringBuffer();
				try {
					sb.append(":");
					sb.append(":");
					sb.append(getEndGroup2());
				} catch (Exception e) {
					e.printStackTrace();
				}		
				resource = new StringRepresentation(sb.toString(), MediaType.TEXT_PLAIN); 
				return resource;
			}
	}


}
